﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SimioAPI;
using SimioAPI.Extensions;
using System.Windows.Forms;
using System.Collections;
using System.Diagnostics;


namespace WLC
{
    class WLCCreateSecondaryOrderStepDefinition : IStepDefinition
    {
        #region IStepDefinition Members

        public IStep CreateStep(IPropertyReaders properties)
        {
            return new WLCCreateSecondaryOrderStep(properties);
        }

        public void DefineSchema(IPropertyDefinitions schema)
        {
            IPropertyDefinition orderID = schema.AddExpressionProperty("OrderID", String.Empty);
            orderID.Description = "The unique number of this order.";
            orderID.Required = true;

            IPropertyDefinition orderSize = schema.AddExpressionProperty("OrderSize", String.Empty);
            orderSize.Description = "The size of this order.";
            orderSize.Required = true;


            IPropertyDefinition itemName = schema.AddElementProperty("IntermediateProductStore", WLCIntermediateProductStoreElementDefinition.ID);
            itemName.Description = "The intermediate store to check if any of the required material is in stock for this order.";
            itemName.Required = true;


            IPropertyDefinition bom = schema.AddElementProperty("BOM", WLCBOMElementDefinition.ID);
            bom.Description = "The bill of material for this order.";
            bom.Required = true;

            
    
        }

        public int NumberOfExits
        {
            get { return 1; }
        }


        public string Name
        {
            get { return "CreateSecondaryOrders"; }
        }

        public string Description
        {
            get { return ""; }
        }

        public System.Drawing.Image Icon
        {
            get { return null; }
        }

    
        public Guid UniqueID
        {
            get { return new Guid("{AC07AF0A-2000-11DF-B3EB-D39455D89593}"); }
        }

        #endregion
    }


    class WLCCreateSecondaryOrderStep : IStep
    {

        
        IElementProperty _productStoreProp;
        IElementProperty _bomProp;
        IPropertyReader _orderIDProp;
        IPropertyReader _orderSizeProp;


        public WLCCreateSecondaryOrderStep(IPropertyReaders bag)
        {

            _productStoreProp = (IElementProperty)bag.GetProperty("IntermediateProductStore");
            _orderIDProp = bag.GetProperty("OrderID");
            _bomProp = (IElementProperty)bag.GetProperty("BOM");
            _orderSizeProp = bag.GetProperty("OrderSize");

        }

        #region IStep Members

        private string GetOrderType(IStepExecutionContext context)
        {
            string rawType = context.AssociatedObject.ExecutionContext.ToString();
            string[] splitType = rawType.Split(' ');

            return splitType[1];
        }

        public ExitType Execute(IStepExecutionContext context)
        {

            context.ExecutionInformation.TraceInformation("CREATESECONDARYORDERS: Entered execution.");

            // Get the order's bill of materials
            WLCBOMElement bom = (WLCBOMElement) _bomProp.GetElement(context);
                                 
            // Get the order ID to create this order for
            string orderID = GetOrderType(context) + "." + ((int)_orderIDProp.GetDoubleValue(context)).ToString();
            double orderSize = (double)_orderSizeProp.GetDoubleValue(context);

            // Get the duedate of the parent order
            double parentDueDate = context.AssociatedObject.States["OrderDueDate"].StateValue;

            // Get the average lead time of the order's type. Must have been set prior to the execution of this step
            double parentAvgLeadTime = context.AssociatedObject.States["OrderAverageLeadTime"].StateValue;
            
            // Get the product store to check for available materials
            WLCIntermediateProductStoreElement productStore = (WLCIntermediateProductStoreElement)_productStoreProp.GetElement(context);
            productStore.NextOrderReservedFor = orderID;


            // Get all entries from the BOM
            Hashtable bomEntries = bom.getBOMEntries();
            int inStock;
            BOMEntry currentEntry;

            foreach (String key in bomEntries.Keys)
            {
                currentEntry = (BOMEntry)bomEntries[key];
                inStock = productStore.InStock(orderID, key);

                context.ExecutionInformation.TraceInformation("CREATESECONDARYORDERS: " + " Time: " + context.Calendar.TimeNow.ToString() + ", Production order " + orderID + ", in stock of Item " + key + ": " + inStock + ", required: " + currentEntry.Amount * orderSize);

                if (inStock < (currentEntry.Amount * orderSize))
                {


                    context.ExecutionInformation.TraceInformation("CREATESECONDARYORDERS: " + "Trying to set state >" + ((IState)currentEntry.CreatingSourceState).Name + 
                        "< to 1, state >" + ((IState)currentEntry.CreatingSourceSizeState).Name + "< to " + ((currentEntry.Amount * orderSize) - inStock));
                    
                    ((IState)currentEntry.CreatingSourceSizeState).StateValue = (currentEntry.Amount * orderSize) - inStock;
                    ((IState)currentEntry.CreatingSourceDueDateState).StateValue = (parentDueDate - parentAvgLeadTime);


                    // Set state to 1 which triggers the production of an order at the source
                    ((IState)currentEntry.CreatingSourceState).StateValue = 1;

                    context.ExecutionInformation.TraceInformation("CREATESECONDARYORDERS: Time: " + context.Calendar.TimeNow.ToString() + ", Triggering a secondary order for production order " + orderID + " over  " + (currentEntry.Amount * orderSize - inStock) + " units of item " + key);
                }
                

            }
            

            
            return ExitType.FirstExit;
        }

        #endregion

    }


}
